﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;

namespace PostProcCalc
{
    public class FileWorker
    {
        private const String ElementsCountConst = "KTR";
        private const String PointsCountConst = "KUZLOV";
        private const String ElementTypeConst = "TYPE";
        private const String BasisTypeConst = "BASIS";

        private int _knotsCount;
        private int _elemCount;
        private int _elemKnots;
        public  int BasisCode;

        #region Ctors

        public FileWorker()
        {
        }

        /// <summary>
        /// Initialize instance of file worker
        /// </summary>
        /// <param name="paramFilePath">inf2tr file path</param>
        public FileWorker(String paramFilePath)
        {
            Init(paramFilePath);
        }

        #endregion

        /// <summary>
        /// Initialize instance of file worker
        /// </summary>
        /// <param name="paramFilePath">inf2tr file path</param>
        public void Init(String paramFilePath)
        {
            if (!File.Exists(paramFilePath))
                throw new Exception(String.Format("File not found {0}", paramFilePath));

            var parameters = new Dictionary<string, int>();

            // Read lines and parse "var=    val"
            using (var sr = new StreamReader(paramFilePath))
            {
                var i = 1;
                while (!sr.EndOfStream)
                {
                    var buf = sr.ReadLine();
                    if (buf == null)
                        continue;

                    var bufwords = buf.Split(' ').ToList();
                    bufwords.RemoveAll(w => w == String.Empty);
                    var words = bufwords.ToArray();

                    // Check for even or odd
                    if (words.Count()%2 != 0)
                        throw new Exception(String.Format("File reading error {0}, line {1}", paramFilePath, i));

                    for (var j = 0; j < words.Count(); j += 2)
                    {
                        if (!words[j].EndsWith("="))
                            continue;
                        var param = words[j].Replace("=", String.Empty);
                        var value = int.Parse(words[j + 1]);

                        parameters.Add(param, value);
                    }

                    i++;
                }
            }

            // Check keys existance
            var keys = new List<String> { ElementsCountConst, PointsCountConst, ElementTypeConst, BasisTypeConst };
            foreach (var key in keys.Where(key => !parameters.Keys.Contains(key)))
            {
                throw new Exception(String.Format("File reading error {0}, expected {1}", paramFilePath, key));
            }

            _knotsCount = parameters[PointsCountConst];
            _elemCount = parameters[ElementsCountConst];
            _elemKnots = parameters[ElementTypeConst];
             BasisCode = parameters[BasisTypeConst];
        }
        
        public IEnumerable<Point> LoadPoints(String pointsFilePath)
        {
            if (!File.Exists(pointsFilePath))
                throw new Exception(String.Format("File not found {0}", pointsFilePath));

            FileInfo testInfo = new FileInfo(pointsFilePath);

            if (testInfo.Length < 2 * _knotsCount * sizeof(Double))
                throw new Exception(String.Format("File {0} has not enought data", pointsFilePath));

            if (testInfo.Length > 2 * _knotsCount * sizeof(Double))
                throw new Exception(String.Format("File {0} has too much data", pointsFilePath));

            var pts = new List<Point>();
            using(var br = new BinaryReader(File.Open(pointsFilePath, FileMode.Open)))
            {
                for(var i=0; i<_knotsCount; ++i)
                {
                    var x = br.ReadDouble();
                    var y = br.ReadDouble();

                    pts.Add(new Point{X = x, Y = y});
                }
            }
            return pts;
        }

        public IEnumerable<int[]> LoadElements(String elementsFilePath)
        {
            if (!File.Exists(elementsFilePath))
                throw new Exception(String.Format("File not found {0}", elementsFilePath));

            FileInfo testInfo = new FileInfo(elementsFilePath);

            if (testInfo.Length < (_elemKnots + 1) * _elemCount * sizeof(Int64)) 
                throw new Exception(String.Format("File {0} has not enought data", elementsFilePath));

            if (testInfo.Length > (_elemKnots + 1) * _elemCount * sizeof(Int64))
                throw new Exception(String.Format("File {0} has too much data", elementsFilePath));

            var elems = new List<int[]>();
            using (var br = new BinaryReader(File.Open(elementsFilePath, FileMode.Open)))
            {
                for (var i = 0; i < _elemCount; ++i)
                {
                    var elem = new int[_elemKnots + 1];
                    for (var j = 0; j < _elemKnots + 1; ++j)
                        elem[j] = (int)br.ReadInt64();

                    elems.Add(elem);
                }
            }
            return elems;
        }

        public double[] LoadSolution(String solFilePath)
        {
            if (!File.Exists(solFilePath))
                throw new Exception(String.Format("File not found {0}", solFilePath));

            FileInfo testInfo = new FileInfo(solFilePath);

            if (testInfo.Length < _knotsCount * sizeof(Double))
                throw new Exception(String.Format("File {0} has not enought data", solFilePath));

            if (testInfo.Length > _knotsCount * sizeof(Double))
                throw new Exception(String.Format("File {0} has too much data", solFilePath));

            var sol = new List<double>();
            using (var br = new BinaryReader(File.Open(solFilePath, FileMode.Open)))
            {
                for (var i = 0; i < _knotsCount; ++i)
                {
                    var x = br.ReadDouble();

                    sol.Add(x);
                }
            }
            return sol.ToArray();
        }

        public String[] LoadMaterialNames(String matFilePath)
        {
            if (!File.Exists(matFilePath))
                throw new Exception(String.Format("File not found {0}", matFilePath));

            var result = new List<String>();
            using(var sr = new StreamReader(File.Open(matFilePath, FileMode.Open)))
            {
                while (!sr.EndOfStream)
                {
                    var buf = sr.ReadLine();
                    var strMat = buf.Split(':');
                    if (strMat.Count() != 2)
                        continue;

                    result.Add(strMat[1].Replace(" ", String.Empty));
                }
            }
            return result.ToArray();
        }
    }
}
